import { _decorator, Component, error, find, instantiate, Node, Prefab, resources } from 'cc';
import { UIBase } from './UIBase';
import Singleton from '../Common/Singleton';
import { ResMgr } from '../Res/ResMgr';
const { ccclass, property } = _decorator;
//层级问题： 每种类型的UI统一挂到对应节点上，再让这些节点去处理层级问题。
// UIRoot根节点： 正常页面，挂件，弹窗...
//管理所有的UI==》所有UI都要继承于一个基类（UIBase）
//打开关闭UI
@ccclass('UIManager')
export class UIManager extends Singleton<UIManager>(){
    //单例
    // private static _instance:UIManager = null;
    // static get instance(){
    //     if(!this._instance){
    //         this._instance = new UIManager();
    //         //UI管理者产生的时候，第一时间就要去吧UI根节点找到，并且分层的节点也需要进行存储。
    //         this._instance._init();
    //     }
    //     return this._instance;
    // }
    //管理所有UI
    private _mapUI:Map<string,UIBase> = new Map();
    //存储UI的层级父亲节点
    private _mapLayer:Map<string,Node> = new Map();

    

    //ui管理者的初始化，主要处理根节点相关：创建，UI层级节点的存储（==》需要去创建一个容器）
    async _init(){
        // 到当前游戏中的Canvas下去找UI根节点
        let uiRoot:any = find('Canvas/UIRoot');
        //搜索子节点存储
        let findLayer = (node:Node)=>{
            let children  =node.children;
            for(let child of children){
                this._mapLayer.set(child.name,child);
            }
        }
        //如果没有找到，那么需要创建实例化。
        if(!uiRoot){
            //那么到资源管理者中找UIFramework包拿UIRoot预制体
            let uiFrameworkBundle = ResMgr.instance.getBundle('UIFramework');
            await ResMgr.instance.getResWithNeed<Prefab>('UIFramework','UIRoot').then((prefab:Prefab)=>{
                if(!prefab){
                    error('UIRoot预制体获取不到');
                    return;
                }
                uiRoot = instantiate(prefab);
                uiRoot.parent = find('Canvas');
            })
            
        }
        //如果找到，那么直接用了
        findLayer(uiRoot);
    }
    // ui名字，
    // 层级的名字
    async openUI(uiName:string,bundleName:string,layerName:string='Normal',...rest:any[]){
        if(!uiName||uiName.length <=0||!bundleName||bundleName.length <=0){
            return;
        }
        //去掉参数1,和2 后的其他参数数组，为了如果打开需要携带数据，可以直接传递给打开的ui
        let args = Array.prototype.slice.call(arguments,2);
        //通过UI名字去查找这个ui是否已经存在
        let ui = this._mapUI.get(uiName);
        //如果ui不存在，那么直接去加载ui
        if(!ui){      
            let uiN:any = null;
            await ResMgr.instance.getResWithNeed<Prefab>(bundleName,uiName).then((prefab:Prefab)=>{
                if(!prefab){
                    error('UIRoot预制体获取不到');
                    return;
                }
                //挂上去
                let parentN = this._mapLayer.get(layerName);
                if(!parentN){
                    error('!ui parent');
                    return;
                }
                uiN = instantiate(prefab);
                uiN.parent = parentN;
                //不要忘记存储UI
                //获取ui
                ui = uiN.getComponent(UIBase);
                //存储ui的名字
                ui.uiName = uiName;
                //存储起来
                this._mapUI.set(uiName,ui);
                //ui打开逻辑。==》分析：不同ui的打开可能初始化逻辑不一样，也不应该写在这里
                //想：所有UI都是在这里打开， ==》多态，基类写一个接口，让派生重写，这里调用基类接口。
                //只调用一次，并且是在实例化之后第一次调用。
                ui.init.apply(ui,args);
            });          
            
        }
        //ui已经存在，重新激活。
        ui.open.apply(ui,args);
    }

    //关闭
    //ui名字,关闭后是否要销毁，携带的数据。
    closeUI(uiName:string,isDestroy:boolean= false,...rest:any[]){
        if(uiName.length <=0){
            return;
        }
        //获取要关闭的ui
        let ui = this._mapUI.get(uiName);
        //找不到ui没法关闭。
        if(!ui){
            return;
        }
        let args = Array.prototype.slice.call(arguments,2);
        //确定这个ui是否在关闭的时候要销毁
        ui.isDestroy = isDestroy;
        //如果当前关闭的这个ui是要被销毁的，那么应该把他从UI管理者的ui容器中移除掉。
        if(isDestroy){
            this._mapUI.delete(uiName);
        }
        //处理这个ui的关闭
        ui.close.apply(ui,args);
    }   

    sendMsg(msgName:string,uiName:string,...rest:any[]){
        let args = Array.prototype.slice.call(arguments,2);
        
        if(uiName.length <=0||!uiName){
            //没有传递UI名字，那么默认所有UI都会接收到消息。
            for(let ui of Array.from(this._mapUI.values())){
                let cb = ui[msgName];
                if(cb){
                    cb.apply(ui,args);
                    continue;
                }
                ui.handleMsg.apply(ui,args);
            }
            return;
        }
        //如果UI有传递名字，那么单独处理这个UI的响应。
        let ui = this._mapUI.get(uiName);
        if(!ui){
            error('响应的UI'+uiName+'不存在');
            return;
        }
        let cb = ui[msgName];
        if(cb){
            cb.apply(ui,args);
            return;
        }
        ui.handleMsg.apply(ui,args);        
    }

}


